home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / SBP2 / FWSBP2Driver / FWSBP2Driver.c next >
Encoding:
C/C++ Source or Header  |  1999-05-17  |  40.4 KB  |  1,371 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWSBP2Driver.c
  3.  
  4.     Contains:    Sample SBP-2 driver
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Eric Anderson
  13.  
  14.         Other Contact:        
  15.  
  16.         Technology:            FireWire
  17.  
  18.     Writers:
  19.  
  20.         (EA)    Eric Anderson (ewa)
  21.         (DCB)    Clinton Bauder
  22.  
  23.     Change History (most recent first):
  24.  
  25.       <FW14>      5/4/99    EA        Added comment regarding driver name (sbp609e,104d8).
  26.       <FW13>      5/4/99    EA        Changed all DelayFor() to DelayForHardware().  DelayFor() can
  27.                                     only be used at Task level and only for durations greater than
  28.                                     16 milliseconds.
  29.       <FW12>     4/17/99    DCB        Use offcial values for the name of the driver.
  30.       <FW11>     1/10/99    EA        Added support for testing cable power management API.
  31.       <FW10>      1/3/99    EA        Changed read block function to append dummy ORB, then a chain of
  32.                                     ORBS, to test non-immediate append.
  33.        <FW9>      1/3/99    EA        Added (and commented out) a simple test of
  34.                                     FWGetSBP2NormalCommandObjectIDFromORB_POINTER.
  35.        <FW8>      1/1/99    EA        Added test of FWGetFWReferenceIDFromUniqueID when we query
  36.                                     logins.  Also allocate memory for our ORB command object.
  37.        <FW7>    12/31/98    EA        Removed DebugStr that reported LUN status.  Note that Query
  38.                                     Logins doesn't report a timeout correctly yet.
  39.        <FW6>    12/31/98    EA        Added support for Query Logins.
  40.        <FW5>    12/31/98    EA        Added support for sending a TARGET RESET management ORB.  Also
  41.                                     set max payload size to 512 (now that FSL enforces it).
  42.        <FW4>    11/18/98    EA        Changed to report LUN.
  43.        <FW3>    10/28/98    DCB        Using new defs for matching SBP drivers. This allows us to be
  44.                                     much more specific in our decision as to which driver belongs to
  45.                                     which device.
  46.        <FW2>     9/20/98    EA        Filled in header comments.
  47.        <FW1>     9/20/98    EA        first checked in
  48. */
  49.  
  50.  
  51. #include <Types.h>
  52. #include <Errors.h>
  53. #include <Devices.h>
  54. #include <DriverServices.h>
  55. #include <FireWire.h>
  56. #include <FireWireSBP2.h>
  57. #include <SampleSBP2.h>
  58. #include <FWSBP2Driver.h>
  59. /*zzz*/
  60. #include <TextUtils.h>
  61. #include <stdio.h>
  62. char    debugStr[256];
  63. /*zzz*/
  64.  
  65.  
  66. ////////////////////////////////////////////////////////////////////////////////
  67. //
  68. // Internal procedure prototypes.
  69. //
  70.  
  71. static OSStatus    FWSBP2Initialize (
  72.     RegEntryIDPtr                pRegEntryID);
  73.  
  74. static OSStatus    FWSBP2Terminate (void);
  75.  
  76. static OSStatus    SBPDriverInterface (
  77.     SBPInterfaceParamsPtr        pSBPInterfaceParams);
  78.  
  79. static OSStatus    SBP2Login (
  80.     SBPLoginParamsPtr            pSBPLoginParams);
  81.  
  82. static OSStatus    SBP2Logout (
  83.     SBPLogoutParamsPtr            pSBPLogoutParams);
  84.  
  85. static OSStatus    SBP2Status (
  86.     SBPStatusParamsPtr            pSBPStatusParams);
  87.  
  88. static OSStatus SBP2DoQueryLogins(
  89.     SBPQueryLoginsParamsPtr    pSBPQueryLoginsParams);
  90.  
  91. static OSStatus SBP2DoStatusInquiry(
  92.     SBPStatusInquiryParamsPtr    pSBPStatusInquiryParams);
  93.  
  94. static OSStatus SBP2DoModeSense(
  95.     SBPModeSenseParamsPtr        pSBPModeSenseParams);
  96.  
  97. static OSStatus SBP2DoReadBlock(
  98.     SBPReadBlockParamsPtr        pSBPReadBlockParams);
  99.  
  100. static OSStatus SBP2DoTargetReset(
  101.     SBPTargetResetParamsPtr        pSBPTargetResetParams);
  102.  
  103. static OSStatus SBP2DoPowerTest(
  104.     SBPPowerTestParamsPtr        pSBPPowerTestParams);
  105.  
  106. static OSStatus SBPLoginNotify(
  107.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  108.     UInt32                        *pCommandAcceptance);
  109.  
  110. static OSStatus SBPStatusNotify(
  111.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  112.     UInt32                        *pCommandAcceptance);
  113.  
  114. static OSStatus SBPUnsolicitedStatusNotify(
  115.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  116.     UInt32                        *pCommandAcceptance);
  117.  
  118. #if 0
  119. static void    SBP2ClientCommandCompletionProc (
  120.     FWCommandObjectID            fwCommandObjectID,
  121.     OSStatus                    commandStatus,
  122.     UInt32                        completionProcData);
  123. #endif
  124.  
  125.  
  126. ////////////////////////////////////////////////////////////////////////////////
  127. //
  128. // The driver descriptor.
  129. //
  130.  
  131. // The driver name sbp609e,104d8 causes this driver to match against
  132. // a device that encapsulate SCSI as per section D.2 of the SBP-2
  133. // standard.  Other driver names would be perfectly valid too, and
  134. // there is no requirement to use SCSI.  This generic driver can log
  135. // in and out of any SBP-2 device.  Some of the other commands in the
  136. // demo application are specific to RBC and 609e,104d8.
  137.  
  138. DriverDescription                 TheDriverDescription =
  139. {
  140.     kTheDescriptionSignature,
  141.     kInitialDriverDescriptor,
  142.     {
  143.         "\psbp609e,104d8",        // Encapsulated SCSI device per SBP2
  144.         1, 0, finalStage, 1,
  145.     },
  146.     {
  147.         kDriverIsUnderExpertControl,
  148.         "\p.FWSBP2Driver",
  149.     },
  150.  
  151.     1,
  152.     kServiceCategoryNdrvDriver,
  153.     kNdrvTypeIsSampleSBP2,
  154.     1,0,0,0
  155. };
  156.  
  157. ////////////////////////////////////////////////////////////////////////////////
  158. //
  159. // A quick note on how this works:
  160. //
  161. // The SBP2Expert creates sub-nodes for each LUN 
  162. // ...:firewire:fw609e,10483
  163. // ...:firewire:fw609e,10483:sbpXXXXXX,YYYYYY
  164. // ...:firewire:fw609e,10483:sbpPPPPPP,QQQQQQ
  165. //
  166. // XXXXXX is the command_set_spec_ID of lun 0.  YYYYYY is the command_set of lun 0.
  167. // PPPPPP is the command_set_spec_ID if lun 1.  QQQQQQ is the command_set of lun 1.  etc.
  168. //
  169. // The name of the driver then should match the sub-node created by the expert. To further
  170. // narrow down the match the SBP2Expert creates a table with the VendorID, SoftwareRev,
  171. // FirmwareRev, LUN and device_type values from the CSR ROM. This table is contained  in
  172. // a property called "TheDFMTable". The format for this table is in FireWireSBP2.h.
  173. // A similar table is exported by the driver and is called TheDFMDescriptor. It is exactly
  174. // twice the size of TheDFMTable as it contains a range for each value exported by the expert.
  175. // Drivers which match the greatest number of values in the table are selected to match the
  176. // device. Fields with a negative range are marked as "don't care". 
  177. //
  178. // Note that "don't care" is different from matching everything. Matching everything means
  179. // the score for the driver will be incremented for that field while don't care means that
  180. // it won't be. Thus a driver with 3 matches and 1 don't care scores lower than a driver
  181. // with 4 matches - even if the matches are the 0 through 0xFFFFFFFF type.
  182. //
  183. // Drivers with identical scores will be ranked by version as with other native drivers.
  184.  
  185. SBPMatchData                        TheDFMDescriptor = 
  186. {
  187.     0xFFFFFFFF, 0x00000000,            // VendorID, match all             (only low 24 bits valid)
  188.     0xFFFFFFFF, 0x00000000,            // SoftwareRev, match all        (only low 24 bits valid)
  189.     0xFFFFFFFF, 0x00000000,            // FirmwareRev, match all         (indicated by negative range)
  190.     0xFFFFFFFF, 0x00000000,            // LUN, match all                 (only low 16 bits valid)
  191.     0xFFFFFFFF, 0x00000000            // device_type, match all         (only low 5 bits valid)
  192. };
  193.  
  194. ////////////////////////////////////////////////////////////////////////////////
  195. //
  196. // Global driver data.
  197. //
  198.  
  199. FWSBP2DriverDataPtr                gpFWSBP2DriverData = nil;
  200.  
  201.  
  202. ////////////////////////////////////////////////////////////////////////////////
  203. //
  204. // DoDriverIO
  205. //
  206. //   Main entry point.
  207. //
  208.  
  209. OSErr    DoDriverIO(
  210.     AddressSpaceID                addressSpaceID,
  211.     IOCommandID                    ioCommandID,
  212.     IOCommandContents            ioCommandContents,
  213.     IOCommandCode                ioCommandCode,
  214.     IOCommandKind                ioCommandKind)
  215. {
  216.     CntrlParamPtr                pCntrlParam;
  217.     OSErr                        err = noErr;
  218.  
  219.     switch (ioCommandCode)
  220.     {
  221.         case kInitializeCommand :
  222.             err = FWSBP2Initialize (&ioCommandContents.initialInfo->deviceEntry);
  223.             break;
  224.  
  225.         case kFinalizeCommand :
  226.             err = FWSBP2Terminate ();
  227.  
  228.         case kOpenCommand :
  229.             break;
  230.  
  231.         case kCloseCommand :
  232.             break;                    //zzz should probably do a logout
  233.  
  234.         case kControlCommand :
  235.             pCntrlParam = (CntrlParamPtr) ioCommandContents.pb;
  236.             if (pCntrlParam->csCode == cscSBPCommand)
  237.             {
  238.                 err = SBPDriverInterface
  239.                         (*((SBPInterfaceParamsPtr *) &(pCntrlParam->csParam[0])));
  240.             }
  241.             else
  242.             {
  243.                 err = controlErr;
  244.             }
  245.             break;
  246.  
  247.         case kStatusCommand :
  248.             err = statusErr;
  249.             break;
  250.  
  251.         default :
  252.             err = paramErr;
  253.     }
  254.  
  255.     // We're complete.
  256.     if (ioCommandKind == kImmediateIOCommandKind)
  257.         return (err);
  258.     else
  259.         return (IOCommandIsComplete (ioCommandID, err));
  260.  
  261.     return (err);
  262. }
  263.  
  264.  
  265. ////////////////////////////////////////////////////////////////////////////////
  266. //
  267. // SBPDriverInterface
  268. //
  269. //   Main driver interface.
  270. //
  271.  
  272. static OSStatus    SBPDriverInterface(
  273.     SBPInterfaceParamsPtr        pSBPInterfaceParams)
  274. {
  275.     UInt32                        interfaceSelector;
  276.     OSStatus                    status = noErr;
  277.  
  278.     // Get some params.
  279.     interfaceSelector = pSBPInterfaceParams->interfaceSelector;
  280.  
  281.     // Note - most real SBP-2 drivers would not have these dispatches.
  282.     // A disk driver would have open, close, read, write - etc.  The
  283.     // driver would decide when to perform a login, mode sense, etc.,
  284.     // without being told to do these specific things.
  285.     
  286.     // Main dispatch.
  287.     switch (interfaceSelector)
  288.     {
  289.         case kSampleSBPLogin :
  290.             status = SBP2Login ((SBPLoginParamsPtr) pSBPInterfaceParams);
  291.             break;
  292.  
  293.         case kSampleSBPLogout :
  294.             status = SBP2Logout ((SBPLogoutParamsPtr) pSBPInterfaceParams);
  295.             break;
  296.  
  297.         case kSampleSBPStatus :
  298.             status = SBP2Status ((SBPStatusParamsPtr) pSBPInterfaceParams);
  299.             break;
  300.  
  301.         case kSampleSBPQueryLogins :
  302.             status = SBP2DoQueryLogins ((SBPQueryLoginsParamsPtr) pSBPInterfaceParams);
  303.             break;
  304.  
  305.         case kSampleSBPStatusInquiry :
  306.             status = SBP2DoStatusInquiry ((SBPStatusInquiryParamsPtr) pSBPInterfaceParams);
  307.             break;
  308.  
  309.         case kSampleSBPModeSense :
  310.             status = SBP2DoModeSense ((SBPModeSenseParamsPtr) pSBPInterfaceParams);
  311.             break;
  312.  
  313.         case kSampleSBPReadBlock :
  314.             status = SBP2DoReadBlock ((SBPReadBlockParamsPtr) pSBPInterfaceParams);
  315.             break;
  316.  
  317.         case kSampleSBPTargetReset :
  318.             status = SBP2DoTargetReset ((SBPTargetResetParamsPtr) pSBPInterfaceParams);
  319.             break;
  320.  
  321.         case kSampleSBPPowerTest :
  322.             status = SBP2DoPowerTest ((SBPPowerTestParamsPtr) pSBPInterfaceParams);
  323.             break;
  324.  
  325.         default :
  326.             status = paramErr;
  327.             break;
  328.     }
  329.  
  330.     return (status);
  331. }
  332.  
  333.  
  334. ////////////////////////////////////////////////////////////////////////////////
  335. //
  336. // FWSBP2Initialize
  337. //
  338. //   This routine initializes the FireWire SBP2 sample driver.  It
  339. // allocates a private data record and registers with the FireWire family.
  340. // It also prepares some command objects for use later on.
  341. //
  342.  
  343. static OSStatus SBPLoginNotify(
  344.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  345.     UInt32                        *pCommandAcceptance);
  346.  
  347. static OSStatus    FWSBP2Initialize(
  348.     RegEntryIDPtr                pRegEntryID)
  349. {
  350.     FWSBP2DriverDataPtr            pFWSBP2DriverData = nil;
  351.     FWDriverID                    fwDriverID;
  352.     OSStatus                    status = noErr;
  353.  
  354.     // Allocate our driver data.
  355.     pFWSBP2DriverData =
  356.         (FWSBP2DriverDataPtr) PoolAllocateResident (sizeof (FWSBP2DriverData), true);
  357.     if (pFWSBP2DriverData == nil)
  358.     {
  359.         status = memFullErr;
  360.     }
  361.  
  362.     // Register with the FireWire family.
  363.     if (status == noErr)
  364.     {
  365.         status = FWRegisterDriver (pRegEntryID,
  366.                                    &fwDriverID,
  367.                                    &(pFWSBP2DriverData->csrUnitID),
  368.                                    (UInt32) pFWSBP2DriverData);
  369.  
  370.         if (status == noErr)
  371.             pFWSBP2DriverData->fwDriverID = fwDriverID;
  372.     }
  373.  
  374.     // Get reference to local node.
  375.     if (status == noErr)
  376.     {
  377.         status = FWGetLocalFWReferenceIDFromFWReferenceID
  378.                     (pFWSBP2DriverData->fwDriverID,
  379.                      &(pFWSBP2DriverData->localFWReferenceID));
  380.     }
  381.  
  382.     // Set the maximum packet payload size.
  383.     if (status == noErr)
  384.     {
  385.         status = FWSetMaxPayloadSize ((FWReferenceID) pFWSBP2DriverData->fwDriverID, 512);
  386.     }
  387.  
  388.     // Allocate login command object.
  389.     if (status == noErr)
  390.     {
  391.         status = FWAllocateSBP2LoginCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  392.                                                    &pFWSBP2DriverData->loginCommandID);
  393.     }
  394.     
  395.     if (status != noErr) pFWSBP2DriverData->loginCommandID = 0;
  396.  
  397.     // Prepare login command object.
  398.     if (status == noErr)
  399.         status = FWSetFWCommandFlags (pFWSBP2DriverData->loginCommandID, kFWCommandSyncFlag);
  400.  
  401.     if (status == noErr)
  402.     {
  403.         status = FWSetSBP2LoginCommandFlags (pFWSBP2DriverData->loginCommandID,
  404.                                              kSBP2NotifyOnLoginComplete |
  405.                                              kSBP2NotifyOnLoginFailed |
  406.                                              kSBP2NotifyOnReconnecting |
  407.                                              kSBP2NotifyOnReconnectComplete |
  408.                                              kSBP2NotifyOnReconnectFailed);
  409.     }
  410.     
  411.     if (status == noErr)
  412.     {
  413.         status = FWSetSBP2LoginCommandMaxPayloadSize (pFWSBP2DriverData->loginCommandID, 512);
  414.     }
  415.  
  416.     if (status == noErr)
  417.     {
  418.         status = FWSetSBP2LoginCommandLoginNotifyProc (pFWSBP2DriverData->loginCommandID,
  419.                                                        SBPLoginNotify,
  420.                                                        (UInt32) pFWSBP2DriverData);
  421.     }
  422.  
  423.     if (status == noErr)
  424.     {
  425.         status = FWSetSBP2LoginCommandStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  426.                                                         SBPStatusNotify,
  427.                                                         (UInt32) pFWSBP2DriverData);
  428.     }
  429.  
  430.     if (status == noErr)
  431.     {
  432.         status = FWSetSBP2LoginCommandUnsolicitedStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  433.                                                                    SBPUnsolicitedStatusNotify,
  434.                                                                    (UInt32) pFWSBP2DriverData);
  435.     }
  436.  
  437.     // Allocate a dummy ORB command object.
  438.     if (status == noErr)
  439.     {
  440.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  441.                                                     &pFWSBP2DriverData->dummyOrbID);
  442.     }
  443.     
  444.     if (status != noErr) pFWSBP2DriverData->dummyOrbID = 0;
  445.     
  446.     if (status == noErr)
  447.         status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->dummyOrbID, 3 * 4096);
  448.  
  449.     // Allocate an ORB command object.
  450.     if (status == noErr)
  451.     {
  452.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  453.                                                     &pFWSBP2DriverData->firstOrbID);
  454.     }
  455.     
  456.     if (status != noErr) pFWSBP2DriverData->firstOrbID = 0;
  457.     
  458.     if (status == noErr)
  459.         status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->firstOrbID, 3 * 4096);
  460.  
  461.     // Allocate another ORB command object.
  462.     if (status == noErr)
  463.     {
  464.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  465.                                                     &pFWSBP2DriverData->orbID);
  466.     }
  467.     
  468.     if (status != noErr) pFWSBP2DriverData->orbID = 0;
  469.     
  470.     if (status == noErr)
  471.         status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->orbID, 3 * 4096);
  472.  
  473.     // Allocate a management ORB command object.
  474.     if (status == noErr)
  475.     {
  476.         status = FWAllocateSBP2ManagementCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  477.                                                         &pFWSBP2DriverData->managementORBID);
  478.     }
  479.     
  480.     if (status != noErr) pFWSBP2DriverData->managementORBID = 0;
  481.     
  482.     // Allocate an asynch command object for writing to the AGENT_RESET register.
  483.     if (status == noErr)
  484.     {
  485.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwAGENT_RESET_ID);
  486.     }
  487.  
  488.     if (status == noErr)
  489.     {
  490.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwAGENT_RESET_ID,
  491.                                        pFWSBP2DriverData->fwDriverID,
  492.                                        kFWCommandSyncFlag,
  493.                                        nil,
  494.                                        0);
  495.     }
  496.  
  497.     // The AGENT_RESET command object will be filled in some more after we get the
  498.     // login response and we learn the address of the fetch agent.
  499.     
  500.     // Allocate an asynch command object for writing to the DOORBELL register.
  501.     if (status == noErr)
  502.     {
  503.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwDOORBELL_ID);
  504.     }
  505.  
  506.     if (status == noErr)
  507.     {
  508.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwDOORBELL_ID,
  509.                                        pFWSBP2DriverData->fwDriverID,
  510.                                        kFWCommandSyncFlag,
  511.                                        nil,
  512.                                        0);
  513.     }
  514.  
  515.     // The DOORBELL command object will be filled in some more after we get the
  516.     // login response and we learn the address of the fetch agent.
  517.     
  518.     // Allocate an asynch command object for reading the ORB_POINTER register.
  519.     if (status == noErr)
  520.     {
  521.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->readORB_POINTER_ID);
  522.     }
  523.  
  524.     if (status == noErr)
  525.     {
  526.         status = FWSetFWCommandParams (pFWSBP2DriverData->readORB_POINTER_ID,
  527.                                        pFWSBP2DriverData->fwDriverID,
  528.                                        kFWCommandSyncFlag,
  529.                                        nil,
  530.                                        0);
  531.     }
  532.  
  533.     // Allocate a Cable Power Management command object
  534.     if (status == noErr)
  535.     {
  536.         status = FWAllocatePowerCommandObject (&pFWSBP2DriverData->powerChangeID);
  537.     }
  538.     
  539.     if (status == noErr)
  540.     {
  541.         status = FWSetFWCommandParams (pFWSBP2DriverData->powerChangeID,
  542.                                        pFWSBP2DriverData->fwDriverID,
  543.                                        kFWCommandSyncFlag,
  544.                                        nil,
  545.                                        0);
  546.     }
  547.  
  548.     if (status == noErr)
  549.     {
  550.         pFWSBP2DriverData->notificationMessage = PoolAllocateResident (1024, true);
  551.         if (!pFWSBP2DriverData->notificationMessage)
  552.             status = memFullErr;
  553.     }
  554.         
  555.     // Make a note of our LUN
  556.     if (status == noErr)
  557.     {
  558.         status = FWGetSBP2LUNFromFWReferenceID (pFWSBP2DriverData->fwDriverID,
  559.                                                 &pFWSBP2DriverData->lun);
  560.  
  561. //sprintf (debugStr, "Driver get status %ld lun %ld",
  562. //         (long) status, (long) pFWSBP2DriverData->lun);
  563. //DebugStr ((ConstStr255Param) c2pstr (debugStr));
  564.  
  565.     }
  566.  
  567.     // Save our driver data or clean up on error.
  568.     if (status == noErr)
  569.     {
  570.         gpFWSBP2DriverData = pFWSBP2DriverData;
  571.     }
  572.     else
  573.     {//zzz should use terminate
  574.         if (pFWSBP2DriverData != nil)
  575.             PoolDeallocate ((Ptr) pFWSBP2DriverData);
  576.     }
  577.  
  578.     return status;
  579. }
  580.  
  581.  
  582. ////////////////////////////////////////////////////////////////////////////////
  583. //
  584. // FWSBP2Terminate
  585. //
  586. //   This routine terminates the FireWire SBP2 sample driver.  It
  587. // deallocates a private data record and unregisters with the FireWire family.
  588. //
  589. // Note, with the sample family and app, this routine is never called.
  590. // Even if you unplug the device, nobody terminates the driver.
  591. //
  592.  
  593. static OSStatus    FWSBP2Terminate(void)
  594. {
  595.     OSStatus                    status = noErr;
  596.  
  597.     if (gpFWSBP2DriverData != nil)
  598.     {
  599.         // Unregister with FireWire family.
  600.         if (gpFWSBP2DriverData->fwDriverID != kInvalidFWDriverID)
  601.             FWUnregisterDriver (gpFWSBP2DriverData->fwDriverID);
  602.  
  603.         //zzz We should check that ORB is not active before we deallocate it.
  604.         // We could issue a target reset to guarantee this.
  605.         
  606.         if (gpFWSBP2DriverData->orbID)
  607.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->orbID);
  608.  
  609.         if (gpFWSBP2DriverData->login)
  610.             FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
  611.         
  612.         if (gpFWSBP2DriverData->loginCommandID)
  613.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->loginCommandID);
  614.  
  615.         // Deallocate our driver data.
  616.         PoolDeallocate ((Ptr) gpFWSBP2DriverData);
  617.         gpFWSBP2DriverData = nil;
  618.     }
  619.  
  620.     return status;
  621. }
  622.  
  623.  
  624. ////////////////////////////////////////////////////////////////////////////////
  625. //
  626. // SBP2Login
  627. //
  628. //   This routine performs a login.
  629. //
  630.  
  631. static OSStatus    SBP2Login(
  632.     SBPLoginParamsPtr            pSBPLoginParams)
  633. {
  634.     OSStatus                    status = noErr;
  635.  
  636.     gpFWSBP2DriverData->reconnectFailed = false;
  637.     gpFWSBP2DriverData->notificationEvent = 0;
  638.     gpFWSBP2DriverData->notificationCounter++;
  639.     
  640.     status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  641.     pSBPLoginParams->status = status;
  642.         
  643.     return noErr;
  644. }
  645.  
  646.  
  647. ////////////////////////////////////////////////////////////////////////////////
  648. //
  649. // SBP2Logout
  650. //
  651. //   This routine performs a logout.
  652. //
  653.  
  654. static OSStatus    SBP2Logout(
  655.     SBPLogoutParamsPtr            pSBPLogoutParams)
  656. {
  657.     OSStatus                    status = noErr;
  658.  
  659.     status = FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
  660.     pSBPLogoutParams->status = status;
  661.     
  662.     if (status == noErr) gpFWSBP2DriverData->login = false;
  663.     gpFWSBP2DriverData->notificationEvent = 0;
  664.     gpFWSBP2DriverData->notificationCounter++;
  665.  
  666.     return noErr;
  667. }
  668.  
  669.  
  670. ////////////////////////////////////////////////////////////////////////////////
  671. //
  672. // SBP2Status
  673. //
  674. //   This routine returns various status.
  675. //
  676.  
  677. static OSStatus    SBP2Status(
  678.     SBPStatusParamsPtr            pSBPStatusParams)
  679. {
  680.     OSStatus                    status = noErr;
  681.  
  682.     pSBPStatusParams->login = gpFWSBP2DriverData->login;
  683.     pSBPStatusParams->reconnecting = gpFWSBP2DriverData->reconnecting;
  684.     pSBPStatusParams->reconnectFailed = gpFWSBP2DriverData->reconnectFailed;
  685.     
  686.     pSBPStatusParams->notificationCounter = gpFWSBP2DriverData->notificationCounter;
  687.     pSBPStatusParams->notificationEvent = gpFWSBP2DriverData->notificationEvent;
  688.     pSBPStatusParams->notificationLength = gpFWSBP2DriverData->notificationLength;
  689.     
  690.     //zzz Driver should not share it's pointer with application.  Should copy buffer instead.
  691.     pSBPStatusParams->notificationMessage = gpFWSBP2DriverData->notificationMessage;
  692.     
  693.     pSBPStatusParams->lun = gpFWSBP2DriverData->lun;
  694.     
  695.     return noErr;
  696. }
  697.  
  698.  
  699. ////////////////////////////////////////////////////////////////////////////////
  700. //
  701. // SBP2DoQueryLogins
  702. //
  703. //   This routine sends a Query Logins management ORB.
  704. // This routine makes only synchronous calls, so it must be called only at task
  705. // level.
  706. //
  707.  
  708. static OSStatus SBP2DoQueryLogins(
  709.     SBPQueryLoginsParamsPtr        pSBPQueryLoginsParams)
  710. {
  711.     FWCommandObjectID            orbID;
  712.     CSRNodeUniqueID                uniqueID;
  713.     OSStatus                    status;
  714.  
  715.     gpFWSBP2DriverData->notificationEvent = 0;
  716.     gpFWSBP2DriverData->notificationCounter++;
  717.     orbID = gpFWSBP2DriverData->managementORBID;
  718.     
  719.     if (status == noErr)
  720.         status = FWSetSBP2ManagementCommandFunction (orbID, kSBP2QueryLogins);
  721.     
  722.     if (status == noErr)
  723.         status = FWSetSBP2ManagementCommandResponseBuffer (orbID, (Ptr) pSBPQueryLoginsParams->response, 256);
  724.     
  725.     if (status == noErr)
  726.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  727.     
  728.     if (status == noErr)
  729.         status = FWSBP2Manage (orbID);
  730.     
  731.     // The Manage command was synchronous.  When it returns, the command has been
  732.     // sent to the target and the target has executed the command.
  733.     
  734.     // Using the first EUI-64 returned (if any), test FWGetFWReferenceIDFromUniqueID
  735.     // to see if it returns the corresponsing fwReferenceID, or an error if the ID is
  736.     // invalid (and thus not found).
  737.     
  738.     if (status == noErr)
  739.     {
  740.         uniqueID.hi = pSBPQueryLoginsParams->response[2];
  741.         uniqueID.lo = pSBPQueryLoginsParams->response[3];
  742.         pSBPQueryLoginsParams->uniqueIDStatus =
  743.             FWGetFWReferenceIDFromUniqueID (gpFWSBP2DriverData->fwDriverID,
  744.                                             uniqueID,
  745.                                             &pSBPQueryLoginsParams->fwReferenceID);
  746.         
  747.         if (pSBPQueryLoginsParams->uniqueIDStatus == noErr)
  748.             status = FWGetUniqueID (pSBPQueryLoginsParams->fwReferenceID,
  749.                                     &pSBPQueryLoginsParams->uniqueID);
  750.     }
  751.     
  752.     pSBPQueryLoginsParams->status = status;
  753.     
  754.     return noErr;
  755. }
  756.  
  757.  
  758. ////////////////////////////////////////////////////////////////////////////////
  759. //
  760. // SBP2DoStatusInquiry
  761. //
  762. //   This routine performs a status inquiry.  With the Symbios SYMFW2500 kit,
  763. // a status inquiry will clear a check condition and allow the drive to be used.
  764. // This routine makes only synchronous calls, so it must be called only at task
  765. // level.
  766. //
  767.  
  768. static OSStatus SBP2DoStatusInquiry(
  769.     SBPStatusInquiryParamsPtr    pSBPStatusInquiryParams)
  770. {
  771.     FWCommandObjectID            orbID;
  772.     FWAddress                    buffers[1];
  773.     UInt32                        lengths[1];
  774.     char                        buffer[256];
  775.     UInt8                        command[12] = {0x03, 0, 0, 0, 0x12, 0, 0, 0, 0, 0, 0, 0};
  776.     OSStatus                    status;
  777.  
  778.     gpFWSBP2DriverData->notificationEvent = 0;
  779.     gpFWSBP2DriverData->notificationCounter++;
  780.     orbID = gpFWSBP2DriverData->orbID;
  781.     
  782.     // Prepare the ORB.
  783.     
  784.     buffers[0].addressHi = 0;
  785.     buffers[0].addressLo = (UInt32) buffer;
  786.     lengths[0] = 18;
  787.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  788.  
  789.     if (status == noErr)
  790.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  791.     
  792.     if (status == noErr)
  793.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  794.     
  795.     if (status == noErr)
  796.         status = FWSetSBP2NormalCommandFlags (orbID,
  797.                                               kSBP2CommandTransferDataFromTarget |
  798.                                               kSBP2CommandImmediate |
  799.                                               kSBP2CommandCompleteNotify);
  800.     
  801.     if (status == noErr)
  802.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  803.     
  804.     if (status == noErr)
  805.         status = FWAppendSBP2Command (orbID);
  806.     
  807.     // The Append command was synchronous.  When it returns, the command has been
  808.     // appended to the target.  But the target probably has not executed the command yet.
  809.     
  810.     if (status == noErr)
  811.     {
  812.         //zzz Just wait for target to execute command.  Should use notification instead.
  813.         DelayForHardware (DurationToAbsolute (durationMillisecond * 1000));
  814.         //should have response by now
  815.     }
  816.     
  817.     // After a Status Inquiry, the SYM13FW2500 will be in the Dead state, so we
  818.     // need to reset the Fetch Agent.
  819.     if (status == noErr)
  820.         status = FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  821.  
  822.     // "buffer" was allocated on the stack.  So it would be very bad to return
  823.     // now if the ORB was still active.
  824.     
  825.     return noErr;
  826. }
  827.  
  828.  
  829. ////////////////////////////////////////////////////////////////////////////////
  830. //
  831. // SBP2DoModeSense
  832. //
  833. //   This routine performs a mode sense.  With the Symbios SYMFW2500 kit,
  834. // a mode sense will return some data about the drive that is connected.
  835. // This routine makes only synchronous calls, so it must be called only at task
  836. // level.
  837. //
  838.  
  839. static OSStatus SBP2DoModeSense(
  840.     SBPModeSenseParamsPtr        pSBPModeSenseParams)
  841. {
  842.     FWCommandObjectID            orbID;
  843.     FWAddress                    buffers[1];
  844.     UInt32                        lengths[1];
  845.     char                        buffer[256];
  846.     UInt8                        command[12] = {0x5a, 0x08, 0x3e, 0, 0, 0, 0, 0, 0xff, 0, 0, 0};
  847.     OSStatus                    status;
  848.  
  849.     gpFWSBP2DriverData->notificationEvent = 0;
  850.     gpFWSBP2DriverData->notificationCounter++;
  851.     orbID = gpFWSBP2DriverData->orbID;
  852.     
  853.     // Prepare the ORB.
  854.     
  855.     buffers[0].addressHi = 0;
  856.     buffers[0].addressLo = (UInt32) buffer;
  857.     lengths[0] = 255;
  858.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  859.  
  860.     if (status == noErr)
  861.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  862.     
  863.     if (status == noErr)
  864.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  865.     
  866.     if (status == noErr)
  867.         status = FWSetSBP2NormalCommandFlags (orbID,
  868.                                               kSBP2CommandTransferDataFromTarget |
  869.                                               kSBP2CommandImmediate);
  870.     
  871.     if (status == noErr)
  872.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  873.     
  874.     if (status == noErr)
  875.         status = FWAppendSBP2Command (orbID);
  876.     
  877.     // The Append command was synchronous.  When it returns, the command has been
  878.     // appended to the target.  But the target probably has not executed the command yet.
  879.     
  880.     if (status == noErr)
  881.     {
  882.         //zzz Just wait for target to execute command.  Should use notification instead.
  883.         DelayForHardware (DurationToAbsolute (durationMillisecond * 1000));
  884.         //should have response by now
  885.     }
  886.  
  887.     // My SYM13FW2500 does not understand the page_table_present bit, so the
  888.     // mode sense does not work (in fact, it tries to write the result onto
  889.     // the page table!)
  890.  
  891.     // "buffer" was allocated on the stack.  So it would be very bad to return
  892.     // now if the ORB was still active.
  893.     
  894.     return noErr;
  895. }
  896.  
  897.  
  898. ////////////////////////////////////////////////////////////////////////////////
  899. //
  900. // SBP2DoReadBlock
  901. //
  902. //   This routine reads block zero, assuming the target is a simple hard drive.
  903. // This routine makes only synchronous calls, so it must be called only at task
  904. // level.
  905. //
  906.  
  907. static OSStatus SBP2DoReadBlock(
  908.     SBPReadBlockParamsPtr        pSBPReadBlockParams)
  909. {
  910.     FWCommandObjectID            orbID, dummyOrbID, firstOrbID;
  911.     FWAddress                    buffers[1];
  912.     UInt32                        lengths[1];
  913.     char                        buffer[4096];
  914.     UInt8                        command[12];
  915.     UInt32                        lba = 0;
  916.     UInt16                        xfer = 1;
  917.     UInt32                        transferIsWrite = 0;
  918.     OSStatus                    status;
  919.  
  920.     gpFWSBP2DriverData->notificationEvent = 0;
  921.     gpFWSBP2DriverData->notificationCounter++;
  922.     dummyOrbID = gpFWSBP2DriverData->dummyOrbID;
  923.     firstOrbID = gpFWSBP2DriverData->firstOrbID;
  924.     orbID = gpFWSBP2DriverData->orbID;
  925.     
  926.     // Prepare a dummy ORB.
  927.     status = FWSetSBP2NormalCommandBuffers (dummyOrbID, 0, 0, 0);
  928.  
  929.     if (status == noErr)
  930.         status = FWSetSBP2NormalCommandFlags (dummyOrbID, kSBP2CommandDummyORB | kSBP2CommandImmediate);
  931.  
  932.     if (status == noErr)
  933.         status = FWSetFWCommandFlags (dummyOrbID, kFWCommandSyncFlag);
  934.     
  935.     // We're actually going to read two blocks, to see if ORB chaining works.
  936.     
  937.     // Prepare first ORB.
  938.     // Page table total length must agree with ATAPI request length, or drive
  939.     // will get confused.
  940.     
  941.     buffers[0].addressHi = 0;
  942.     buffers[0].addressLo = (UInt32) buffer;
  943.     lengths[0] = 512;
  944.     if (status == noErr)
  945.         status = FWSetSBP2NormalCommandBuffers (firstOrbID, 1, buffers, lengths);
  946.  
  947.     // Form ATAPI command (SCSI-3, cribbed from MMC-2 spec)
  948.     command[0] = (transferIsWrite ? 0x2A : 0x28);    // Write or Read
  949.     command[1] = 0;                                    // Mostly reserved
  950.     command[2] = (lba >> 24) & 0xff;                // MSB of LBA
  951.     command[3] = (lba >> 16) & 0xff;
  952.     command[4] = (lba >> 8) & 0xff;
  953.     command[5] = lba & 0xff;                        // LSB of LBA
  954.     command[6] = 0;                                    // Reserved
  955.     command[7] = (xfer >> 8) & 0xff;                // MSB of block count
  956.     command[8] = xfer & 0xff;                        // LSB of block count
  957.     command[9] = 0;                                    // Control (reserved)
  958.     command[10] = 0;
  959.     command[11] = 0;
  960.  
  961.     if (status == noErr)
  962.         status = FWSetSBP2NormalCommandCommand (firstOrbID, (Ptr) command, 12);
  963.     
  964.     if (status == noErr)
  965.         status = FWSetSBP2NormalCommandTimeout (firstOrbID, durationMillisecond * 100);
  966.     
  967.     if (status == noErr)
  968.         status = FWSetSBP2NormalCommandFlags (firstOrbID,
  969.                                               (transferIsWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
  970.                                               kSBP2CommandCompleteNotify);
  971.  
  972.     if (status == noErr)
  973.         status = FWSetFWCommandFlags (firstOrbID, kFWCommandSyncFlag);
  974.     
  975.     // Second of two transfer ORBs
  976.     // Everything was copied into the ORB so we can recycle the arguments immediately.
  977.     buffers[0].addressLo = 512 + (UInt32) buffer;
  978.     command[5] = (lba+1) & 0xff;                        // LSB of LBA
  979.     
  980.     if (status == noErr)
  981.         status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  982.  
  983.     if (status == noErr)
  984.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  985.     
  986.     if (status == noErr)
  987.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 100);
  988.     
  989.     if (status == noErr)
  990.         status = FWSetSBP2NormalCommandFlags (orbID,
  991.                                               (transferIsWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
  992.                                               kSBP2CommandCompleteNotify);
  993.  
  994.     if (status == noErr)
  995.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  996.     
  997.     //////////////////
  998.     // Time for action
  999.     
  1000.     if (status == noErr)
  1001.         status = FWAppendSBP2Command (dummyOrbID);
  1002.     
  1003.     // The Append command was synchronous.  When it returns, the command has been
  1004.     // appended to the target.  But the target probably has not executed the command yet.
  1005.     
  1006.     if (status == noErr)
  1007.     {
  1008.         //zzz Just wait for target to execute command.  Should use notification instead.
  1009.         DelayForHardware (DurationToAbsolute (durationMillisecond * 100));
  1010.         //should have response by now
  1011.     }
  1012.  
  1013.     // Put two real ORBs on the list...
  1014.     
  1015.     if (status == noErr)
  1016.         status = FWAppendSBP2Command (firstOrbID);
  1017.     
  1018.     if (status == noErr)
  1019.         status = FWAppendSBP2Command (orbID);
  1020.     
  1021.     // Now we need to ring the doorbell to make the target wake up.
  1022.     
  1023.     if (status == noErr)
  1024.         status = FWWrite (gpFWSBP2DriverData->fwDOORBELL_ID);
  1025.     
  1026.     if (status == noErr)
  1027.     {
  1028.         //zzz Just wait for target to execute command.  Should use notification instead.
  1029.         DelayForHardware (DurationToAbsolute (durationMillisecond * 100));
  1030.         //should have response by now
  1031.     }
  1032.  
  1033.     // My SYM13FW2500 does not understand the page_table_present bit, so this
  1034.     // command does not work.  Probably my unit has old firmware.
  1035.  
  1036.     // This command works on the Seagate FireWire hard drive.
  1037.     
  1038.     // "buffer" was allocated on the stack.  So it would be very bad to return
  1039.     // now if the ORB was still active.
  1040.  
  1041. #define ORB_POINTER_TEST 0
  1042.  
  1043. #if ORB_POINTER_TEST
  1044.     if (status == noErr)
  1045.     {
  1046.         FWCommandObjectID        returnID;
  1047.         FWAddress                ORB_POINTER;
  1048.  
  1049.         status = FWSetAsynchCommandParams
  1050.             (gpFWSBP2DriverData->readORB_POINTER_ID,
  1051.              0,                                                    // generation - ignored
  1052.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1053.              gpFWSBP2DriverData->fetchAgent.addressLo + 8,        // + 8 to get ORB_POINTER
  1054.              (Ptr) &ORB_POINTER,                                // put result here
  1055.              8,                                                    // block read
  1056.              0,                                                    // max payload - ignored
  1057.              8,                                                    // max retries
  1058.              0);                                                // no flags
  1059.         
  1060.         // We set the synchronous flag when we allocated the object, and we set the max payload
  1061.         // size to 512 already, so we're all set:
  1062.         
  1063.         if (status == noErr)
  1064.             status = FWRead (gpFWSBP2DriverData->readORB_POINTER_ID);
  1065.  
  1066.         // When I tried this, everything worked fine except the drive sent back 00000000.00000001
  1067.         // as its ORB pointer, which obviously is wrong.  Forcing the result like this works:
  1068.         //ORB_POINTER.addressHi = 8;
  1069.         //ORB_POINTER.addressLo = 0;
  1070.         // This particular drive is not honoring SBP-2 9.1.4 where it says that when reaching a
  1071.         // null pointer the fetch agent should go into SUSPENDED state and the ORB_POINTER
  1072.         // register should contain the address of the ORB containing the null pointer.  Oh well.
  1073.  
  1074.         sprintf (debugStr, "Read of ORB_POINTER status = %ld, result = %08lx.%08lx",
  1075.                  (long) status, (long) ORB_POINTER.addressHi, (long) ORB_POINTER.addressLo);
  1076.         DebugStr ((ConstStr255Param) c2pstr (debugStr));
  1077.         
  1078.         if (status == noErr)
  1079.             status = FWGetSBP2NormalCommandObjectIDFromORB_POINTER (gpFWSBP2DriverData->loginCommandID,
  1080.                                                                     ORB_POINTER,
  1081.                                                                     &returnID);
  1082.  
  1083.         sprintf (debugStr, "Get...POINTER status = %ld, result = %08lx, real ORB ID = %08lx",
  1084.                  (long) status, (long) returnID, (long) orbID);
  1085.         DebugStr ((ConstStr255Param) c2pstr (debugStr));        
  1086.     }
  1087. #endif
  1088.  
  1089.     return noErr;
  1090. }
  1091.  
  1092.  
  1093. ////////////////////////////////////////////////////////////////////////////////
  1094. //
  1095. // SBP2DoTargetReset
  1096. //
  1097. //   This routine sends a TARGET RESET management ORB.
  1098. // This routine makes only synchronous calls, so it must be called only at task
  1099. // level.
  1100. //
  1101.  
  1102. static OSStatus SBP2DoTargetReset(
  1103.     SBPTargetResetParamsPtr        pSBPTargetResetParams)
  1104. {
  1105.     FWCommandObjectID            orbID;
  1106.     OSStatus                    status;
  1107.  
  1108.     gpFWSBP2DriverData->notificationEvent = 0;
  1109.     gpFWSBP2DriverData->notificationCounter++;
  1110.     orbID = gpFWSBP2DriverData->managementORBID;
  1111.     
  1112.     if (status == noErr)
  1113.         status = FWSetSBP2ManagementCommandFunction (orbID, kSBP2TargetReset);
  1114.     
  1115.     if (status == noErr)
  1116.         status = FWSetSBP2ManagementCommandCommandID (orbID, gpFWSBP2DriverData->loginCommandID);
  1117.     
  1118.     if (status == noErr)
  1119.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1120.     
  1121.     if (status == noErr)
  1122.         status = FWSBP2Manage (orbID);
  1123.     
  1124.     // The Manage command was synchronous.  When it returns, the command has been
  1125.     // sent to the target and the target has executed the command.
  1126.         
  1127.     // SBP-2 says the fetch agent will be dead after a RESET_TARGET, so reset it too.
  1128.     
  1129.     if (status == noErr)
  1130.         status = FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1131.         
  1132.     return noErr;
  1133. }
  1134.  
  1135.  
  1136. ////////////////////////////////////////////////////////////////////////////////
  1137. //
  1138. // DummyPowerNotify
  1139. //
  1140. //   This is what a notification proc would look like (except a real one
  1141. // would probably do something useful.
  1142. //
  1143.  
  1144. static OSStatus    DummyPowerNotify (
  1145.     FWClientPowerNotifyParamsPtr    pPowerNotifyParams,
  1146.     UInt32                            *pCommandAcceptance)
  1147. {
  1148.     // Do something useful here.
  1149.     
  1150.     
  1151.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1152.     return FWClientCommandIsComplete (pPowerNotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1153. }
  1154.  
  1155.  
  1156. ////////////////////////////////////////////////////////////////////////////////
  1157. //
  1158. // SBP2DoPowerTest
  1159. //
  1160. //   This routine tests FWChangePower.  This just tests that the calls work,
  1161. // it doesn't really do anything.  This should return noErr if run on a
  1162. // Yosemite, and no real drivers are really using power.
  1163. //
  1164. // This routine makes only synchronous calls, so it must be called only at task
  1165. // level.
  1166. //
  1167.  
  1168. static OSStatus SBP2DoPowerTest(
  1169.     SBPPowerTestParamsPtr        pSBPPowerTestParams)
  1170. {
  1171.     FWCommandObjectID            powerID;
  1172.     UInt32                        minVolts, reqWatts, allocWatts, flags;
  1173.     FWClientPowerNotifyProcPtr    fwClientPowerNotifyProc;
  1174.     OSStatus                    powerStatus;
  1175.     OSStatus                    status;
  1176.  
  1177.     gpFWSBP2DriverData->notificationEvent = 0;
  1178.     gpFWSBP2DriverData->notificationCounter++;
  1179.     powerID = gpFWSBP2DriverData->powerChangeID;
  1180.         
  1181.     // Imagine our device wants no less than 10 Volts (100 deciVolts)
  1182.     // and 5 Watts (50 deciWatts).
  1183.     
  1184.     if (status == noErr)
  1185.         status = FWSetPowerCommandParams (powerID, 100, 50, 0, 0);
  1186.     
  1187.     if (status == noErr)
  1188.         status = FWSetFWClientPowerNotifyProc (gpFWSBP2DriverData->fwDriverID, &DummyPowerNotify);
  1189.         
  1190.     if (status == noErr)
  1191.         powerStatus = status = FWChangePower (powerID);
  1192.             
  1193.     if (status == noErr)
  1194.         status = FWGetPowerCommandParams (powerID, &minVolts, &reqWatts, &allocWatts, &flags);
  1195.     
  1196.     // Just test that the parameters survived and that we got our 5.0 Watts
  1197.     if (status == noErr)
  1198.     {
  1199.         if (minVolts != 100) status = notFoundErr;
  1200.         if (reqWatts != 50) status = notFoundErr;
  1201.         if (allocWatts != 50) status = notFoundErr;
  1202.         if (flags != 0) status = notFoundErr;
  1203.  
  1204.     }
  1205.     
  1206.     if (status == noErr)
  1207.         status = FWGetFWClientPowerNotifyProc (gpFWSBP2DriverData->fwDriverID,
  1208.                                                &fwClientPowerNotifyProc);
  1209.     
  1210.     // Make sure the notification proc is what we set it to be.
  1211.     if ((status == noErr) && (fwClientPowerNotifyProc != DummyPowerNotify))
  1212.         status = notFoundErr;
  1213.     
  1214.     // Give back the power if we got any
  1215.     if (powerStatus == noErr)
  1216.     {
  1217.         powerStatus = FWSetPowerCommandParams (powerID, 0, 0, 0, 0);
  1218.         
  1219.         if (powerStatus == noErr)
  1220.             powerStatus = FWChangePower (powerID);
  1221.     }
  1222.     
  1223.     // We don't actually want any notification.
  1224.     if (status == noErr)
  1225.         status = FWSetFWClientPowerNotifyProc (gpFWSBP2DriverData->fwDriverID,
  1226.                                                (FWClientPowerNotifyProcPtr) 0);
  1227.         
  1228.     pSBPPowerTestParams->status = status;
  1229.     
  1230.     return noErr;
  1231. }
  1232.  
  1233.  
  1234. ////////////////////////////////////////////////////////////////////////////////
  1235. //
  1236. // SBPLoginNotify
  1237. //
  1238. //   This routine is called when a login command completes.
  1239. //
  1240.  
  1241. static OSStatus SBPLoginNotify(
  1242.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1243.     UInt32                        *pCommandAcceptance)
  1244. {
  1245.     OSStatus                    status;
  1246.     
  1247.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginComplete)
  1248.     {
  1249.         gpFWSBP2DriverData->login = true;
  1250.         gpFWSBP2DriverData->fetchAgent.addressHi =
  1251.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 1);
  1252.         gpFWSBP2DriverData->fetchAgent.addressLo =
  1253.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 2);
  1254.         
  1255.         // Now that we know the fetch agent address, finish setting up the
  1256.         // command objects for writing AGENT_RESET, and DOORBELL
  1257.         
  1258.         status = FWSetAsynchCommandParams
  1259.             (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1260.              0,                                                    // generation - ignored
  1261.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1262.              gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1263.              (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1264.              4,                                                    // quadlet write
  1265.              0,                                                    // max payload - ignored
  1266.              8,                                                    // max retries
  1267.              0);                                                // no flags
  1268.  
  1269.         status = FWSetAsynchCommandParams
  1270.             (gpFWSBP2DriverData->fwDOORBELL_ID,
  1271.              0,                                                    // generation - ignored
  1272.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1273.              gpFWSBP2DriverData->fetchAgent.addressLo + 16,        // + 16 to get DOORBELL
  1274.              (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1275.              4,                                                    // quadlet write
  1276.              0,                                                    // max payload - ignored
  1277.              8,                                                    // max retries
  1278.              0);                                                // no flags
  1279.     }
  1280.     
  1281.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2Reconnecting)
  1282.     {
  1283.         gpFWSBP2DriverData->reconnecting = true;
  1284.     }
  1285.     
  1286.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectComplete)
  1287.     {
  1288.         gpFWSBP2DriverData->reconnecting = false;
  1289.     }
  1290.     
  1291.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectFailed)
  1292.     {
  1293.         gpFWSBP2DriverData->reconnecting = false;
  1294.         gpFWSBP2DriverData->reconnectFailed = true;
  1295.     }
  1296.     
  1297.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1298.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1299. }
  1300.  
  1301.  
  1302. ////////////////////////////////////////////////////////////////////////////////
  1303. //
  1304. // SBPStatusNotify
  1305. //
  1306. //   This routine is called when an ORB generates status.
  1307. //
  1308.  
  1309. static OSStatus SBPStatusNotify(
  1310.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1311.     UInt32                        *pCommandAcceptance)
  1312. {
  1313.     gpFWSBP2DriverData->notificationCounter++;
  1314.     gpFWSBP2DriverData->notificationEvent = pFWClientSBP2NotifyParams->notificationEvent;
  1315.     gpFWSBP2DriverData->notificationLength = pFWClientSBP2NotifyParams->length;
  1316.     if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length))
  1317.         BlockCopy (pFWClientSBP2NotifyParams->message,
  1318.                    gpFWSBP2DriverData->notificationMessage,
  1319.                    pFWClientSBP2NotifyParams->length);
  1320.         
  1321.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1322.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1323. }
  1324.  
  1325.  
  1326. ////////////////////////////////////////////////////////////////////////////////
  1327. //
  1328. // SBPUnsolicitedStatusNotify
  1329. //
  1330. //   This routine is called when an unsolicited status is received.
  1331. //
  1332.  
  1333. static OSStatus SBPUnsolicitedStatusNotify(
  1334.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1335.     UInt32                        *pCommandAcceptance)
  1336. {
  1337.     gpFWSBP2DriverData->notificationCounter++;
  1338.     gpFWSBP2DriverData->notificationEvent = pFWClientSBP2NotifyParams->notificationEvent;
  1339.     gpFWSBP2DriverData->notificationLength = pFWClientSBP2NotifyParams->length;
  1340.     if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length))
  1341.         BlockCopy (pFWClientSBP2NotifyParams->message,
  1342.                    gpFWSBP2DriverData->notificationMessage,
  1343.                    pFWClientSBP2NotifyParams->length);
  1344.  
  1345.  
  1346.     // Should now reset the Unsolocited Status Enabler - or else we'll never get any more.
  1347.     // This driver just receives one to prove that it can be done.
  1348.  
  1349.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1350.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1351. }
  1352.  
  1353.  
  1354. #if 0
  1355. ////////////////////////////////////////////////////////////////////////////////
  1356. //
  1357. // SBP2ClientCommandCompletionProc
  1358. //
  1359. //   This routine does generic completion of FireWire client commands that
  1360. // make asynchronous FireWire service calls.
  1361. //
  1362.  
  1363. static void    SBP2ClientCommandCompletionProc(
  1364.     FWCommandObjectID            fwCommandObjectID,
  1365.     OSStatus                    commandStatus,
  1366.     UInt32                        completionProcData)
  1367. {
  1368.     FWClientCommandIsComplete ((FWClientCommandID) completionProcData,  commandStatus);
  1369. }
  1370. #endif
  1371.